'''
        Created on Jun 14, 2011
        
        @author: Kathy Benitez
        '''
        
if __name__ == '__main__':
 pass########################
#
# Copyright 2011, Vanderbilt University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#       http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS"
# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied.  See the License for the specific languaged governing 
# permissions and limitations under the License.
#
########################

###
#
# This file contains the functions necessary to access the database
# And maybe interact with it too?
#
###

import time
import cPickle as pickle
import csv
from operator import or_
import policyEvaluation
import vdartUtils
import settings
import datetime

"""
Dataset will appear in a pickled form, already translated
into the language of the Population Statistics, P

ds

Also, will need a pickled form of the prior searches/
prior queries.

prior

Each search is an object with its own dataset ds,
a variable indicating what the current policy is.

"""    
class SearchSolution():
    def __init__(self, vocabulary, solutions, cutoffValue, elapsedTime, desc, nodesSearched, nodesEvaluated, searchPaths):
	self.constraints=False
        self.vocab = vocabulary
        self.solutions = solutions
        self.cutoffValue = cutoffValue
        self.elapsedTime = elapsedTime
        self.basicDescription = desc
        self.nodesSearched = nodesSearched
        self.nodesEvaluated = nodesEvaluated
        self.searchPaths = searchPaths

class PolSearch():      #chance pathToDS to dset, pathToPrior=prior
#changed cutoffvalue to cutoffValue, added self.polSize
    from displayUtils import Tri
    def __init__(self, dset, fields, vocab, ps,\
                 weightingFn,prior=pickle.load(open(settings.pathToPrior)), description="", \
                 numToFind = 100, cutoffValue = 0,
                 polSize = 9):
        self.solutionPolicies = []
	self.polSize=polSize
#added self.vocab/fields
	self.fields=fields
	self.vocab=vocab
        self.weightingFn = weightingFn
        self.numToFind=numToFind
        self.e = policyEvaluation.Evaluator(vocab, fields, dset, prior, ps)
	self.prior=self.e.prior
        self.startTime = None 
        self.cutoffValue = cutoffValue
        self.description = description
        self.nodesSearched = None
        self.nodesEvaluated = None
        self.searchPaths=[]
	self.firstCall=True
    def saveState(self):
#change prior directory
        p = open(settings.pathToPrior, 'w')
        pickle.dump(self.prior, p)
        p.close()
    def interimReport(self, currentPolicy):
        print "Have found %i solutions"%(len(self.solutionPolicies))
        print "Storing current policy, prior in temp directory"
        print "Elapsed time %i minutes"%((time.time() - self.startTime)/60)
        self.saveState()
	#changed prior directory to be determined by settings.py
        curr = open(settings.pathToCurr, 'w')
        pickle.dump(currentPolicy, curr)
        curr.close()
 
    def finalReport(self):
        elapsedTime = time.time() - self.startTime
	################ only for my testing purposes
	#f=open('/Users/Alec_/vdart2/data/elapsedTimes.txt','a')
	#f.write(str(elapsedTime))	
	#f.write('\n')
	#f.close()
	###############
        print "Found %i policies in %i minutes"%(len(self.solutionPolicies),
                                                 elapsedTime / 60)
        saveFilePath =settings.saveFilePath + datetime.datetime.now().strftime("%m-%d_%H:%M:%S")
        #changed self.prevpol to self.e.prevpol
        toSave = SearchSolution(self.vocab, \
                         dict([(p, self.e.previousPolicies[p]) for p in self.solutionPolicies]), \
                         self.cutoffValue,\
                         elapsedTime, \
                         self.description, \
                         self.nodesSearched, \
                         self.nodesEvaluated,
                         self.searchPaths)
        s = open(saveFilePath, 'w')
        pickle.dump(toSave, s)
        s.close()
        print "Details can be found at %s"%(saveFilePath)    
        
    def search(self):

        self.nodesSearched = 0
        self.nodesEvaluated = 0
        self.startTime = time.time()
	ph=policyEvaluation.PolicyHandler(self.vocab,self.fields)
	#(below) gives user ability to add initial constraints 
	#genPolicy=vdartUtils.contraints(self.vocab,self.fields,ph.vocabLists,self.polSize) #uncomment when using constraints
        while (len(self.solutionPolicies) < self.numToFind) and \
              (time.time() - self.startTime < 86400):
            searchPath = []
            #general = genPolicy   #uncomment when using constraints
	    general= policyEvaluation.PolicyString.mostGeneral(self.polSize) #comment out when using constraints
            specific= policyEvaluation.PolicyString.mostSpecific(self.polSize)
            while (policyEvaluation.PolicyString.levelsBetween(general, specific) > 2):
                searchPath.append((general, specific))
                newPolicy = policyEvaluation.PolicyString.halfpoint(general, specific, self.weightingFn(self.solutionPolicies, self.polSize,self.vocab,self.fields))
		
                self.interimReport(newPolicy)
                self.nodesSearched += 1
#changed self.e.belowThreshold
		
                isAcceptable = self.isPolicyAcceptable(newPolicy)
                if isAcceptable:
                    general = newPolicy
                else:
                    specific = newPolicy
            if self.isPolicyAcceptable(general):
                #test whether solution is dominating (in which case, remove
                #dominated policies), dominated (don't add), or stand-alone (add
                #to list of solutions)
                self.solutionPolicies.append(general)
                dominated = [p for p in self.solutionPolicies if policyEvaluation.PolicyString.isGen(p,general)]
                for p in dominated:
                    self.solutionPolicies.remove(p)
#changed policystring to policyEvaluation 
                if reduce(or_, [policyEvaluation.PolicyString.isGen(general,p) for p in self.solutionPolicies]):
                    self.solutionPolicies.remove(general)
            self.searchPaths.append(searchPath)
	if self.firstCall:
		if settings.saveFilePath[len(settings.saveFilePath)-1]=='/':
			self.policyPath=settings.saveFilePath+datetime.datetime.now().strftime("%m-%d_%H:%M:%S")+'Policy'
			returnFile=open(self.policyPath,'w')
		else:
			self.policyPath=settings.saveFilePath+'/'+datetime.datetime.now().strftime("%m-%d_%H:%M:%S")+'Policy'
			returnFile=open(self.policyPath,'w')
		returnFile.write(str(self.solutionPolicies))
		returnFile.close()
		self.finalReport()
	self.firstCall=False
	#prompt for policy display
	print('Your policies can be found at'+self.policyPath)
	print('\n')
	userin=True
	while(userin):
		userString=raw_input('Do you want to display the policies found? (Y/N): ')
		userString=userString.upper()
		if userString=='Y':
			userin=False
			displayPols=True
		if userString=='N':
			userin=False
			displayPols=False
		if not (userString=='Y' or userString=='N'):
			print('Incorrect input. Please type Y or N')
        if (displayPols):
		self.displayPolicies()
	return self.solutionPolicies

    def displayPolicies(self):
	#displays 3d graph of policies
	from Tkinter import Tk
	import displayUtils
	pFile=open(self.policyPath,'r')
	policies=vdartUtils.extractPols(pFile.read())
	displayUtils.Tri(Tk(),policies,self.vocab,self.fields)
	


    def isPolicyAcceptable(self, newPolicy):
        """
        policy is acceptable if a specification is acceptable.
        Policy is not acceptable if a generalization is not acceptable.
        Otherwise, must evaluate the policy itself
        
        """
	#changed self.prevpol to self.e.prevpol
	#change'policystring.' to 'policyEvaluation'
	
        if newPolicy in self.e.previousPolicies:
#added [newPolicy] to prevPol
            return self.e.previousPolicies[newPolicy] <= self.cutoffValue
        if reduce(or_, [policyEvaluation.PolicyString.isSpecification(p, newPolicy) and \
                        self.e.previousPolicies[p] <= self.cutoffValue \
                        for p in self.e.previousPolicies], False):
            return True
        if reduce(or_, [policyEvaluation.PolicyString.isGeneralization(p, newPolicy) and \
                        self.e.previousPolicies[p] > self.cutoffValue \
                        for p in self.e.previousPolicies], False):
            return False
        else:
	    
            """ evaluate the policy """
            value = self.e.evaluatePolicy(newPolicy) 
            self.nodesEvaluated += 1
            self.e.previousPolicies[newPolicy] = value
            return value <= self.cutoffValue 

    def policyCutoff(self, policy):
        self.cutoffValue = self.e.evaluatePolicy(policy)
    
